#include <stdio.h>
#include <stdlib.h>


/* Function prototypes */
void checksum(void);
void putch(unsigned char);
unsigned char gx(void);
unsigned char g2x(void);
void zap(void);
void table_write(void);
void flash8(void);
void clear_buffer(void);

unsigned char addru,addrh,addrl;
unsigned char buff[8];  /* Internal buffer used for writing to program memory */
unsigned char idx;
unsigned char data;

unsigned char cksum,rectype,bcount;



/* Get a 4 bit HEX number from the serial port */
unsigned char gx(void){
	unsigned char c;
	c=fgetc(stdin);
	if(c>='A')
		return ((c - (unsigned char)'A')+10);
	return (c - '0');
}

/* recieve a hexadecimal byte, add it to the checksum */
unsigned char g2x(void)
{
	unsigned char temp = (gx()<<4);
	temp += gx();
	cksum+=temp;
	return temp;
}

/* check the checksum 
* NOTE: if not in verbose mode, the code will use the even more compact
* assembler version of the checksum() function defined above.
*/

void checksum(void) {
	g2x();
	if(cksum)       // if checksum does not add to zero, bad check, rese/
	{
		fprintf(stdout, "Checksum mismatch\n");
	}
}

void cfg_write()  {
	fprintf(stdout,"CFG [%02x,%02x,%02x]%02d\n",addru,addrh,addrl,data);
}
void pgm_erase() {
	;
}
void pgm_write8() {
	fprintf(stdout,"PGM [%02x,%02x,%02x]",addru,addrh,addrl);

	for(idx=0;idx<8;idx++)
	{       
		fprintf(stdout,"%02x ",buff[idx]);
	}
	fprintf(stdout,"\nPGM [%02x,%02x,%02x]\n",addru,addrh,addrl);
}
void eep_write() {
	fprintf(stdout,"EEP [%02x,%02x,%02x]%02d\n",addru,addrh,addrl,data);
}

void clear_buffer(void)  {
	for(idx=8;idx--;){
		buff[idx]=0xFF;   // initialize buffer with known values
	}
}

//  **************  Main Routine  *************************
enum states { __IDLE, __DO_FLASH, __END } state;

void main(void)  {
	unsigned char c,i,flash8,erased;

	erased=0;
	state=__IDLE;
	while(state!=__END) {
		switch(state) {
		case __IDLE:
			c=fgetc(stdin);
			if(c=='!') { // Erase buffer
				if(!erased) {
					pgm_erase();
					erased=1;
				}
				state=__IDLE;
			} else if(c==':') {
				// I got a start line
				clear_buffer();
				cksum=0;
				state=__DO_FLASH;
			} else if(c==0xFF) {
				state=__END;
			} else state=__IDLE;
			break;
		case __DO_FLASH:
			// get byte count
			bcount=g2x();
			// get addr
			addrh=g2x();
			addrl=g2x();
			// get record type
			rectype=g2x();

			switch (rectype) {
			case 0x00: // data
				flash8=0;
				while(bcount) {
					data=g2x();
					bcount--;
					switch(addru&0xF0) {
					case 0x30: // write config bits;
						cfg_write();
						break;
					case 0xF0:
						eep_write();
						break;
					case 0x00:
						i=(addrl&0x07);
						buff[i]=data;
						if((i==0x07)||(bcount==0)) {
							pgm_write8();
							clear_buffer();
						} 
						break;
					}
					addrl++;
				}
				checksum();
				state=__IDLE;
				break;
			case 0x01: // eof
				checksum();
				state=__END;
				break;
			case 0x04: // addr
				while(bcount--) {
					addru=g2x();
				}
				checksum();
				state=__IDLE;
				break;
			}
			break;
		}

	}
}
